Skip to content

fix(serve): reject unsafe CORS origins (wildcard + credentials) at startup (GHSA-5mh2, 0.62.1)#422

Open
padak wants to merge 1 commit into
mainfrom
fix/serve-cors-credentials-guard
Open

fix(serve): reject unsafe CORS origins (wildcard + credentials) at startup (GHSA-5mh2, 0.62.1)#422
padak wants to merge 1 commit into
mainfrom
fix/serve-cors-credentials-guard

Conversation

@padak

@padak padak commented Jun 14, 2026

Copy link
Copy Markdown
Member

Summary

Fixes M6 from the 2026-06-12 security audit (private advisory GHSA-5mh2-6xgr-rf89) — a permissive-CORS misconfiguration in kbagent serve.

create_app registers CORSMiddleware with allow_credentials=True. Combined with a wildcard --cors-origin '*' (or a malformed origin), Starlette reflects the request Origin back and returns Access-Control-Allow-Credentials: true — the textbook unsafe combination that lets any website read authenticated cross-origin responses from a victim's running serve. The previous code passed cors_origins straight into the middleware with no validation.

Fix

create_app now validates the origins via _resolve_cors_origins:

  • rejects * and any value that isn't a concrete scheme://host[:port] (no path/query/fragment, per the CORS Origin spec), raising ConfigError;
  • the default (no --cors-origin) localhost dev set is unchanged, so normal use is unaffected — only the actively-dangerous wildcard/malformed config is refused.

kbagent serve catches the ConfigError and surfaces it as a clean typer.BadParameter usage error on --cors-origin (exit 2) instead of a traceback. The guard lives in create_app (the point where the credentialed middleware is configured) so the unsafe combination can't ship via any caller.

No regex / new imports in app.py — the origin check is a small structural predicate.

Tests

New TestCorsCredentialsGuard in test_serve_ui.py: parametrized rejection of ["*"], a mixed list containing *, a scheme-less origin, an origin with a path, and a ws:// origin; parametrized acceptance of None (defaults) and explicit http(s)://host[:port] lists; plus a unit test of the _is_valid_cors_origin predicate. Full suite green: 4021 passed, 132 skipped; lint/format/ty/changelog clean.

Audit progress

Open advisories after this: M7 (silent plaintext-on-encrypt write — spans config/variables/data-app services), M8 (SSRF), M10 (version regex), plus the M5 residual (accepted) and M1 residual. M9 (npm --ignore-scripts) also remains.


Open in Devin Review

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@padak padak force-pushed the fix/serve-cors-credentials-guard branch from d9cbf53 to a9f2ba9 Compare June 17, 2026 20:13
…artup (0.62.1)

create_app sets allow_credentials=True. Combined with `--cors-origin '*'` (or a
malformed origin) Starlette reflects the request Origin and returns
Access-Control-Allow-Credentials: true, letting any website read authenticated
cross-origin responses.

Validate the origins in create_app: reject `*` and any non scheme://host[:port]
value (raising ConfigError), surfaced by `kbagent serve` as a clean
--cors-origin usage error. The default localhost dev set is unaffected.

Private advisory GHSA-5mh2-6xgr-rf89.
@padak padak force-pushed the fix/serve-cors-credentials-guard branch from a9f2ba9 to 39c60be Compare June 17, 2026 21:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant